package com.cmccsi.uc.session;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;

import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentMap;

import org.apache.log4j.Logger;

import com.cmccsi.uc.redis.Const;
import com.cmccsi.uc.redis.IRedisCsync;
import com.cmccsi.uc.redis.RedisCsync;
import com.google.common.collect.MapMaker;
import com.thn.netty.chat.*;
import com.thn.netty.chat.codec.CommandCodec;
import com.thn.netty.chat.codec.IMPB;
import com.thn.netty.chat.codec.IMPB.Presence;
import com.thn.netty.chat.primitive.Command;
import com.thn.netty.chat.primitive.ErroCode;
import com.thn.netty.chat.primitive.PacketType;
import com.thn.netty.chat.server.ChannelInfo;
import com.thn.netty.chat.server.ExecRedisCmdErr;
import com.thn.netty.chat.server.LoginParam;
public class SessionManager implements ISessionManager {

	private static String g_session_mutex = "0";
	private static int SINGLE_SESSION_COUNT = 3;

	private static int KP_UNKNOWN = -1;
	private static int KP_SEND_KICKOUT = -2;
	private static int KP_CLOSE_SOCKET = -3;
	private static int KP_REPEATED_LOGINED = 409;
	private static int KP_SESSION_EXPIRED = 410;	

	private static ConcurrentMap<CONN, SESSION> g_mapConnSessions=new MapMaker()
	.concurrencyLevel(8).makeMap();

	private static final Logger LOGGER = Logger.getLogger(SessionManager.class
			.getName());
	
	private static IRedisCsync psyncR=new RedisCsync();
	
	private static ConcurrentMap<Integer, SESSION> g_mapUseridSessions = new MapMaker()
			.concurrencyLevel(8).makeMap();

	private SESSION FIND_SESSION_CONST(int ulUserid) {
		return g_mapUseridSessions.get(ulUserid);
	}

	private String GET_LOGIN_TYPE_STR(int ucLoginDevice) {
		String loginType = ((ucLoginDevice == IMPB.Presence.DEVICE_TYPE.PC_VALUE) ? "PC"
				: ((ucLoginDevice == IMPB.Presence.DEVICE_TYPE.ANDROID_VALUE || ucLoginDevice == IMPB.Presence.DEVICE_TYPE.IOS_VALUE) ? "MOBILE"
						: ((ucLoginDevice == IMPB.Presence.DEVICE_TYPE.WEB_VALUE) ? "WEB"
								: "UNKNOWN")));

		return loginType;
	}
	

	
	
	@Override
	public Boolean GetSessionid(int ulUserid, String[] szSessionids, int usCount) {
		// TODO Auto-generated method stub		
		try {
			synchronized(g_session_mutex)
			{
				SESSION pSession=FIND_SESSION_CONST(ulUserid);			
				int usCountTemp = usCount;
				int usIndex = 0;
				do {				
					szSessionids[usIndex++]=pSession.getLoginParam().getSzSessionId();
				}while (pSession.getpNextSession()!= null && --usCountTemp > 0);
				usCount = usIndex;		
			}
			return true;
		} catch (Exception e) {
			// TODO: handle exception
			LOGGER.error("查找Sessionid GetSessionid出錯，出錯的Userid："+ulUserid);
			return false;
		}
	}

	@Override
	public SESSION GetSession(int ulUserid) {
		// TODO Auto-generated method stub
		try {
			synchronized(g_session_mutex)
			{
				return FIND_SESSION_CONST(ulUserid);		
			}
		} catch (Exception e) {
			// TODO: handle exception
			LOGGER.error("查找Sessionid GetSessionid出錯，出錯的Userid："+ulUserid);
			return null;
		}
	}
    private void sendNotif(final Command aCommand, ChannelHandlerContext aTargetContext) {
        ChannelFuture future = aTargetContext.writeAndFlush(aCommand);
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture aFuture) throws Exception {
                LOGGER.info("Sent notif: " + aCommand);
            }
        });
    }
//	返回值类型 ERR_PC_BUFFER_WRITE
//	ERR_MOBILE_BUFFER_WRITE
//	ERR_WEB_BUFFER_WRITE
//	ERR_PC_MOBILE_BUFFER_WRITE
//	ERR_PC_WEB_BUFFER_WRITE
//	ERR_WEB_MOBILE_BUFFER_WRITE
//	ERR_PC_WEB_MOBILE_BUFFER_WRITE
	@Override
	public int SendData(int ulUserid, IMPB.Message data, int size, CONN[] ppConnOutput,
			int pConnOutputCount, int ucDeviceType) {
		// TODO Auto-generated method stub
		CONN[] pConn=new CONN[SINGLE_SESSION_COUNT];
		int[] ucLoginTypes =new int[SINGLE_SESSION_COUNT];
		int[] ucDeviceTypes=new int[SINGLE_SESSION_COUNT];
		int usEventCount = 0;
		
		try {
			synchronized(g_session_mutex)
			{
				SESSION pSession= FIND_SESSION_CONST(ulUserid);
				do 
				{
					if ((pSession != null) && (pSession.getOwner()!= null)) 
					{
						pConn[usEventCount] = pSession.getOwner();
						if (ppConnOutput != null)
							ppConnOutput[usEventCount] = pSession.getOwner();
						ucLoginTypes[usEventCount] = pSession.getLoginParam().getUcLoginType();
						ucDeviceTypes[usEventCount] = pSession.getLoginParam().getUcLoginDevice();
						usEventCount++;
					}
				} while (pSession.getpNextSession()!= null && usEventCount < SINGLE_SESSION_COUNT );
			}
		} catch (Exception e) {
			// TODO: handle exception
			LOGGER.error("查找Sessionid GetSessionid出錯，出錯的Userid："+ulUserid);
			return 0;
		}
		int nRet = 0;
		int nResult = (usEventCount == 0) ? ErroCode.ERR_CANNOT_GET_CONN_FROM_USERID.getValue() : 0;
		if(pConnOutputCount>0)
		{
			pConnOutputCount = usEventCount;
		}
		for (int i = 0; i < usEventCount; i++) 
		{
			if(ucDeviceType != ucDeviceTypes[i] && ucDeviceType != 0)
				continue;
			ChannelInfo recipientChannelInfo=pConn[i].getChannelInfo();
			if (recipientChannelInfo != null) {
                // recipient existing and logged in: send the message as a notification  
        		// 拼接报文消息体的protobuf字节流
				
				byte[] datas=data.toByteArray();
        		ByteBuffer bContent = ByteBuffer.allocate(datas.length);
        		bContent.put(datas);    		
        		ByteBuf buf = Unpooled.copiedBuffer(bContent);                  
                Command notif=new Command(PacketType.CMD_FUNCTION_MESSAGE,buf); 
                ChannelHandlerContext recipientContext = recipientChannelInfo.getContext();
                sendNotif(notif, recipientContext);
            } 
			
			
			if (nRet != 0) {
				switch (ucLoginTypes[i])
				{
				case LoginParam.LT_PC:
					nResult = ((nResult == 0) ? ErroCode.ERR_PC_BUFFER_WRITE.getValue()
							: (nResult == ErroCode.ERR_MOBILE_BUFFER_WRITE.getValue() ? ErroCode.ERR_PC_MOBILE_BUFFER_WRITE.getValue()
							: (nResult == ErroCode.ERR_WEB_BUFFER_WRITE.getValue() ? ErroCode.ERR_PC_WEB_BUFFER_WRITE.getValue()
							: (nResult == ErroCode.ERR_WEB_MOBILE_BUFFER_WRITE.getValue()) ? ErroCode.ERR_PC_WEB_MOBILE_BUFFER_WRITE.getValue()
							: ErroCode.ERR_PC_BUFFER_WRITE.getValue())));
					break;
				case LoginParam.LT_MOBILE:
					nResult = ((nResult == 0) ? ErroCode.ERR_MOBILE_BUFFER_WRITE.getValue()
						: (nResult == ErroCode.ERR_PC_BUFFER_WRITE.getValue() ? ErroCode.ERR_PC_MOBILE_BUFFER_WRITE.getValue()
						: (nResult == ErroCode.ERR_WEB_BUFFER_WRITE.getValue() ? ErroCode.ERR_WEB_MOBILE_BUFFER_WRITE.getValue()
						: (nResult == ErroCode.ERR_PC_WEB_BUFFER_WRITE.getValue()) ? ErroCode.ERR_PC_WEB_MOBILE_BUFFER_WRITE.getValue()
						: ErroCode.ERR_MOBILE_BUFFER_WRITE.getValue())));
					break;
				case LoginParam.LT_WEB:
					nResult = ((nResult == 0) ? ErroCode.ERR_WEB_BUFFER_WRITE.getValue()
						: (nResult == ErroCode.ERR_MOBILE_BUFFER_WRITE.getValue() ? ErroCode.ERR_WEB_MOBILE_BUFFER_WRITE.getValue()
						: (nResult == ErroCode.ERR_PC_BUFFER_WRITE.getValue() ? ErroCode.ERR_PC_WEB_BUFFER_WRITE.getValue()
						: (nResult == ErroCode.ERR_PC_MOBILE_BUFFER_WRITE.getValue()) ? ErroCode.ERR_PC_WEB_MOBILE_BUFFER_WRITE.getValue()
						: ErroCode.ERR_WEB_BUFFER_WRITE.getValue())));
					break;
				default:
					nResult = ErroCode.ERR_PARAM_UNKNOWN_LOGINTYPE.getValue();
					break;
				}
			}
			
		}
		
		
		return nResult;
	}

	@Override
	public int SendMsg(CONN pSenderConn, int ulUserid, IMPB.Message data, int size,
			Boolean bSendToMyConn, CONN[] ppConnOutput, int pConnOutputCount) {
		// TODO Auto-generated method stub
		if (bSendToMyConn) {
			return SendData(ulUserid, data, size, ppConnOutput,
					pConnOutputCount, 0);

		} else {
			CONN[] pConn = new CONN[SINGLE_SESSION_COUNT];
			int[] ucLoginTypes = new int[SINGLE_SESSION_COUNT];
			int nResult = 0;
			int usEventCount = 0;
			try {
				synchronized (g_session_mutex) {
					SESSION pSession = FIND_SESSION_CONST(ulUserid);
					{

						do {
							if ((pSession != null)
									&& (pSession.getOwner() != null)
									&& (pSenderConn != pSession.getOwner())) {
								pConn[usEventCount] = pSession.getOwner();
								if (ppConnOutput != null)
									ppConnOutput[usEventCount] = pSession
											.getOwner();
								ucLoginTypes[usEventCount] = pSession
										.getLoginParam().getUcLoginType();
								usEventCount++;
							} else if (pSession.getOwner() != null) {
								nResult = ErroCode.ERR_IGNORE_MYCONN.getValue();
							}
						} while ((pSession = pSession.getpNextSession()) != null
								&& usEventCount < SINGLE_SESSION_COUNT);
					}

				}

			} catch (Exception e) {
				// TODO: handle exception
				LOGGER.error("SendMsg出錯，出錯的Userid：" + ulUserid);
				return 0;
			}

			int nRet = 0;
			nResult = ((usEventCount == 0) && (nResult != 0)) ? nResult
					: ((usEventCount == 0) ? ErroCode.ERR_CANNOT_GET_CONN_FROM_USERID
							.getValue() : 0);
			if (pConnOutputCount != 0)
				pConnOutputCount = usEventCount;
			for (int i = 0; i < usEventCount; i++) {
				ChannelInfo recipientChannelInfo = pConn[i].getChannelInfo();
				if (recipientChannelInfo != null) {
					// recipient existing and logged in: send the message as a
					// notification
					// 拼接报文消息体的protobuf字节流

					byte[] datas = data.toByteArray();
					ByteBuffer bContent = ByteBuffer.allocate(datas.length);
					bContent.put(datas);
					ByteBuf buf = Unpooled.copiedBuffer(bContent);
					Command notif = new Command(
							PacketType.CMD_FUNCTION_MESSAGE, buf);
					ChannelHandlerContext recipientContext = recipientChannelInfo
							.getContext();
					sendNotif(notif, recipientContext);
				}
				if (nRet != 0) {
					switch (ucLoginTypes[i]) {
					case LoginParam.LT_PC:
						nResult = ((nResult == 0) ? ErroCode.ERR_PC_BUFFER_WRITE
								.getValue()
								: (nResult == ErroCode.ERR_MOBILE_BUFFER_WRITE
										.getValue() ? ErroCode.ERR_PC_MOBILE_BUFFER_WRITE
										.getValue()
										: (nResult == ErroCode.ERR_WEB_BUFFER_WRITE
												.getValue() ? ErroCode.ERR_PC_WEB_BUFFER_WRITE
												.getValue()
												: (nResult == ErroCode.ERR_WEB_MOBILE_BUFFER_WRITE
														.getValue()) ? ErroCode.ERR_PC_WEB_MOBILE_BUFFER_WRITE
														.getValue()
														: ErroCode.ERR_PC_BUFFER_WRITE
																.getValue())));
						break;
					case LoginParam.LT_MOBILE:
						nResult = ((nResult == 0) ? ErroCode.ERR_MOBILE_BUFFER_WRITE
								.getValue()
								: (nResult == ErroCode.ERR_PC_BUFFER_WRITE
										.getValue() ? ErroCode.ERR_PC_MOBILE_BUFFER_WRITE
										.getValue()
										: (nResult == ErroCode.ERR_WEB_BUFFER_WRITE
												.getValue() ? ErroCode.ERR_WEB_MOBILE_BUFFER_WRITE
												.getValue()
												: (nResult == ErroCode.ERR_PC_WEB_BUFFER_WRITE
														.getValue()) ? ErroCode.ERR_PC_WEB_MOBILE_BUFFER_WRITE
														.getValue()
														: ErroCode.ERR_MOBILE_BUFFER_WRITE
																.getValue())));
						break;
					case LoginParam.LT_WEB:
						nResult = ((nResult == 0) ? ErroCode.ERR_WEB_BUFFER_WRITE
								.getValue()
								: (nResult == ErroCode.ERR_MOBILE_BUFFER_WRITE
										.getValue() ? ErroCode.ERR_WEB_MOBILE_BUFFER_WRITE
										.getValue()
										: (nResult == ErroCode.ERR_PC_BUFFER_WRITE
												.getValue() ? ErroCode.ERR_PC_WEB_BUFFER_WRITE
												.getValue()
												: (nResult == ErroCode.ERR_PC_MOBILE_BUFFER_WRITE
														.getValue()) ? ErroCode.ERR_PC_WEB_MOBILE_BUFFER_WRITE
														.getValue()
														: ErroCode.ERR_WEB_BUFFER_WRITE
																.getValue())));
						break;
					default:
						nResult = ErroCode.ERR_PARAM_UNKNOWN_LOGINTYPE
								.getValue();
						break;
					}
				}
			}

			return nResult;
		}	
	}

	@Override
	public SESSION CreateSession() {
		// TODO Auto-generated method stub		
		return new SESSION();
	}

	@Override
	public void DestroySession(SESSION pSession) {
		// TODO Auto-generated method stub
		pSession=null;		
	}

	@Override
	public Boolean AddSession(CONN pConn, LoginParam loginParam,
			Boolean pbAddLoginNum) {
		// TODO Auto-generated method stub
		if (pConn == null || loginParam == null) {
			pbAddLoginNum = false;
			return false;
		}

		// 检查sessionid是否合法
		if (loginParam.getSzSessionId().length() != 32) {
			SendKickOutCmd(pConn, KP_SESSION_EXPIRED);
			LOGGER.info("AddSession failed sessionid = "
					+ loginParam.getSzSessionId());
			return false;
		}

		// 检查sessionid是否在redis里
		int nRet = 0;
		ExecRedisCmdErr rtValue = new ExecRedisCmdErr();
		String szUserid = "";
		// String strSessionId;
		szUserid = String.format("%lu_%s", loginParam.getUlUserid(),
				GET_LOGIN_TYPE_STR(loginParam.getUcLoginType()));

		StringBuffer strSessionId = new StringBuffer("");
		psyncR.getUserSession(szUserid, strSessionId, rtValue);

		// 比较sessionid
		if (nRet != 0 || strSessionId.toString() != loginParam.getSzSessionId()) {
			SendKickOutCmd(pConn, KP_SESSION_EXPIRED);
			LOGGER.info(String
					.format("AddSession szUserid = %s, sessionid = %s failed nRet= %d \n",
							szUserid, loginParam.getSzSessionId(), nRet));
			return false;
		}
		LOGGER.info(String.format("AddSession sessionid = %s successfully\n",
				loginParam.getSzSessionId()));

		// 修改已添加的要删除的SessionId
		// 插入预删除表

		psyncR.deletePreDelSession(strSessionId.toString(), rtValue);
		LOGGER.info("deletePreDelSession = " + strSessionId);

		String OldvalueStr = pConn.getOwner().getPmapSessionId().get(szUserid);
		String newValueStr = "";
		if (OldvalueStr != null && OldvalueStr == loginParam.getSzSessionId()) {
			// Add the word firstly, initial the value as 1
			newValueStr = OldvalueStr + Const.STR_CANCEL_DEL_SESSION_ID;
			if (pConn.getOwner().getPmapSessionId()
					.replace(szUserid, OldvalueStr, newValueStr)) {
				return false;
			}
		}

		String NewVStr = pConn.getOwner().getPmapNewSessionId()
				.get(szUserid);
		if (NewVStr != null && NewVStr == loginParam.getSzSessionId()) {
			if (pConn.getOwner().getPmapNewSessionId().remove(szUserid) != null) {
				return false;
			}
		}

		SESSION pSession = CreateSession();
		if (pSession == null) {
			pbAddLoginNum = false;
			return false;
		}
		LoginParam logpram = pSession.getLoginParam();
		logpram.setSzSessionId(loginParam.getSzSessionId());

		logpram.setUlUserid(loginParam.getUlUserid());
		logpram.setUcLoginType(loginParam.getUcLoginType());
		logpram.setUcLoginStatus(loginParam.getUcLoginStatus());
		logpram.setUcLoginDevice(loginParam.getUcLoginDevice());
		logpram.setUcLoginNetworkType(loginParam.getUcLoginNetworkType());
		logpram.setUsLoginFreeswitchConn(loginParam.getUsLoginFreeswitchConn());

		pSession.setLoginParam(logpram);

		pSession.setOwner(pConn);
		pSession.setConnected(true);
		pSession.setpNextSession(null);// 通常为空， 当多类型客户端登录后不为空

		return AddSession(pSession, pbAddLoginNum);
			
	}

	private Boolean LookOverOneSession(SESSION pSession, SESSION pSessionThis, SESSION pSessionLast, SESSION itSessionFound, Boolean bCheckLoginType) {
			
		SESSION itSession=  FIND_SESSION_CONST(pSession.getLoginParam().getUlUserid());
			{
			pSessionThis = null;
			pSessionLast = null;
			itSessionFound = itSession;
			if (itSession == pSession) {
				pSessionThis = pSession;
			}
			else {
				if (bCheckLoginType) {
					// 判断登录类型
					if (itSession!=null && pSession!=null && (itSession.getLoginParam().getUcLoginType() == pSession.getLoginParam().getUcLoginType())) {
						pSessionThis = itSession;
					}
				}
				if (null == pSessionThis) {
					pSessionLast = itSession;
					pSessionThis = pSessionLast.getpNextSession();
					while (pSessionThis != null && pSessionThis != pSession
							&& (!bCheckLoginType || (bCheckLoginType && pSessionThis.getLoginParam().getUcLoginType() != pSession.getLoginParam().getUcLoginType()))) {
						pSessionLast = pSessionThis;
						pSessionThis = pSessionLast.getpNextSession();
					}
					if (pSessionThis == null || (pSessionThis != pSession
							&& (!bCheckLoginType || (bCheckLoginType && pSessionThis.getLoginParam().getUcLoginType() != pSession.getLoginParam().getUcLoginType())))) {
						return false;
					}
				}

			}
			return true;
		}
		return false;
	}

	
	private int GetPushStatus(int usLoginStatus) {
		int ucLoginStatus = 255;
		for (int i = 0; i < Integer.SIZE; i++) {
			ucLoginStatus = ((usLoginStatus >> (i * 8)) & 0xFF);
			if (ucLoginStatus > 0) {
				break;
			}
		}
		return ucLoginStatus;
	}

	private int GetPushDeviceType(int usDeviceType) {
		int ucDeviceType = 0;
		for (int i = 0; i < 32; i++) {
			ucDeviceType = ((usDeviceType >> i) & 0x1);
			if (ucDeviceType > 0) {
				ucDeviceType = i+1;
				break;
			}
		}
		return ucDeviceType;
	}
	private int PushToAllSubscribers(CONN pConn, int ulUserid, int usLoginStatus, int usLoginDeviceType, int usNetworkType) {
		short ucPushStatus = (short) GetPushStatus(usLoginStatus);
		short ucPushDeviceType = (short) GetPushDeviceType(usLoginDeviceType);

		LOGGER.info(String.format("PushToAllSubscribers: %ld, %d, %d\n", ulUserid,
					ucPushStatus, ucPushDeviceType));

		if (!LoginParam.Presence_TYPE_IsValid(ucPushStatus) || !LoginParam.Presence_DEVICE_TYPE_IsValid(ucPushDeviceType) || !LoginParam.Presence_NETWORK_TYPE_IsValid(usNetworkType)) {
			LOGGER.info("PushToAllSubscribers param value is not in the range of protobuf emum!\n");
			return ErroCode.ERR_PROTOBUF_ENUM_INVALID.getValue();
		}

		// push status to subscriber
		List<Integer> lstUsers;
		String strData;
		int akgid = PacketType.CMD_FUNCTION_SET_PRESENCE.id();
		int nPkgLen = 0;
		int nHeadBufLen = 0;
		String strHead;
		IMPB.Message sessionMessage;
		sessionMessage=IMPB.Message.newBuilder().setType(IMPB.Message.TYPE.PRESENCE_PUB).setSubType(IMPB.Message.SUB_TYPE.PRESENCE_PUB_CHANGED)
        .build();        

		IMPB.Presence presence;
		presence=IMPB.Presence.newBuilder().setUserid(ulUserid).setPresence(IMPB.Presence.TYPE.valueOf(ucPushStatus))
				.setDeviceType(IMPB.Presence.DEVICE_TYPE.valueOf(ucPushDeviceType))
				.setNetworkType(IMPB.Presence.NETWORK_TYPE.valueOf(usNetworkType))
				.build();
		nPkgLen = strData.length();
		
		
		char head_out_buf[64] = { 0 };
		
		GetRepHeadStr(akgid, nPkgLen, head_out_buf, nHeadBufLen);
		
		char out_buf[CONN_BUF_LEN] = {0};
		
		memcpy(out_buf, head_out_buf, nHeadBufLen);
		
		memcpy(out_buf+nHeadBufLen, strData.c_str(), strData.size());
		
		const void* pstrData = (void*)out_buf;
		
		size_t size = nHeadBufLen + strData.size();
		sint32 nRet = 0;
		
		if (0 == (nRet = GetSubscriber(pConn, ulUserid, lstUsers,"PC"))) {
			size_t i = 0;
			while(i < size)
			{
				RAW_LOG(INFO,"%02x ",out_buf[i]);
				i++;
			}
			RAW_LOG(INFO,"\n");
			// push status to all subscriber
			std::list<uint64>::const_iterator itUser = lstUsers.begin();
			for (; itUser != lstUsers.end(); ++itUser) {
				nRet = SendData(*itUser, pstrData, size,NULL,NULL,im::Presence_DEVICE_TYPE_PC);
				RAW_LOG(INFO,"PC Push To Subscriber: %ld  \n", *itUser);
			}
		}
		if (0 == (nRet = GetSubscriber(pConn, ulUserid, lstUsers,"ANDROID"))) {
			size_t i = 0;
			while(i < size)
			{
				RAW_LOG(INFO,"%02x ",out_buf[i]);
				i++;
			}
			RAW_LOG(INFO,"\n");
			// push status to all subscriber
			std::list<uint64>::const_iterator itUser = lstUsers.begin();
			for (; itUser != lstUsers.end(); ++itUser) {
				nRet = SendData(*itUser, pstrData, size,NULL,NULL,im::Presence_DEVICE_TYPE_ANDROID);
				RAW_LOG(INFO,"ANDROID Push To Subscriber: %ld \n ", *itUser);
			}
		}
		if (0 == (nRet = GetSubscriber(pConn, ulUserid, lstUsers,"IOS"))) {
			size_t i = 0;
			while(i < size)
			{
				RAW_LOG(INFO,"%02x ",out_buf[i]);
				i++;
			}
			RAW_LOG(INFO,"\n");
			// push status to all subscriber
			std::list<uint64>::const_iterator itUser = lstUsers.begin();
			for (; itUser != lstUsers.end(); ++itUser) {
				nRet = SendData(*itUser, pstrData, size,NULL,NULL,im::Presence_DEVICE_TYPE_IOS);
				RAW_LOG(INFO,"IOS Push To Subscriber: %ld \n ", *itUser);
			}
		}
		return nRet;
	}
	
	
	@Override
	public Boolean AddSession(SESSION pSession, Boolean pbAddLoginNum) {
		// TODO Auto-generated method stub
		if (pSession == null)
		{
			pbAddLoginNum = false;
			return false;
		}
		pbAddLoginNum = false;
		Boolean bKickout = false;
		
		SESSION pSessionThis = null;
		SESSION pSessionLast = null;
		{
			synchronized (g_session_mutex) {
				g_mapConnSessions.put(pSession.getOwner(), pSession);
			}
			
			
			
			MAP_USERID_SESSIONS::iterator itSessionFound = g_mapUseridSessions.end();
			if (!LookOverOneSession(pSession, &pSessionThis, &pSessionLast, itSessionFound, true)){
				//  当session没有前置和后继
				if (itSessionFound != g_mapUseridSessions.end()) {
					pSessionLast->pNextSession = pSession;
					SESSION* pSessionIOS = itSessionFound->second;
					*pbAddLoginNum = true;
					// judge if ios logins and doesn't logout
					while (pSessionIOS != NULL) {
						if (pSessionIOS->connected) {
							pbAddLoginNum = false;
							break;
						}
						pSessionIOS = pSessionIOS->pNextSession;
					}
				}
				else {
					g_mapUseridSessions.insert(MAP_USERID_SESSIONS::value_type(pSession->loginParam.ulUserid, pSession));
					*pbAddLoginNum = true;
				}
			}
			else {
				if (pSessionThis != NULL)
					g_mapConnSessions.erase(pSessionThis->owner);
				// 踢掉原有相同登录类型的连接
				if (pSessionThis != pSession) {
					if (pSessionLast != NULL) {

						pSessionLast->pNextSession = pSession;

						bKickout = true;


					}
					else {
						if (itSessionFound != g_mapUseridSessions.end()) {
							pSession->pNextSession = itSessionFound->second->pNextSession;
							itSessionFound->second = pSession;
							bKickout = true;

						}

					}

				}
				*pbAddLoginNum = false;
			}
		}

		if (bKickout) {
			//
			if (pSessionThis->owner != NULL) {
				SendKickOutCmd(pSessionThis->owner, KP_REPEATED_LOGINED);
			}
			// 以前为苹果推送状态
			else if (pSessionThis->loginParam.ucLoginStatus == LS_DISCONNECTED)
			{
				MutexObject mutex(&g_IosPushUserIdMutex);
				g_IosPushUserIdMap.erase(pSessionThis->loginParam.ulUserid);
			}

			// 清除占用内存
			DestroySession(pSessionThis);

		}
		PresenceRedis pr;
		uint32 usSetWhichValue = EPRSV_PRESENCE | EPRSV_DEVICE | EPRSV_NETWORKTYPE | EPRSV_FREESWITCHCONN;

		pr.usPresencePresence = pSession->loginParam.ucLoginStatus;
		pr.usPresenceDeviceType = pSession->loginParam.ucLoginDevice;
		pr.usPresenceNetworkType = pSession->loginParam.ucLoginNetworkType;
		pr.usPresenceFreeswitchConnType = pSession->loginParam.usLoginFreeswitchConn;
		//LOG(INFO) << "pr.usPresenceFreeswitchConnType: " << pr.usPresenceFreeswitchConnType << "\n";
		return SetUserPresence(pSession->owner, pSession->loginParam.ulUserid, &pr, usSetWhichValue);
		
		return null;
	}

	@Override
	public void CheckSession(SESSION pSession) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void ClearSession() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Boolean RemoveSession(SESSION pSession, Boolean bRemoveFromMap,
			Boolean bLogout, int ulUserid, PresenceRedis pr, String pSessionId) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Boolean RemoveSession(CONN pConn, Boolean bLogout,
			Boolean pbUserOffline) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int GetUserLoginType(int ulUserid) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int GetUserLoginDeviceType(CONN pConn) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int GetUserStatus(CONN pConn, int ulUserid, int ucLoginType) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int GetUserStatus(CONN pConn, int ulUserid) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int SetUserStatus(CONN pConn, int ucLoginStatus) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int SetUserPresence(CONN pConn, int ulUserid, PresenceRedis pr,
			int usSetWhichValue) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int SetUserPresence(CONN pConn, PresenceRedis pr, int usSetWhichValue) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Boolean IsOnIOSPushStatus(int ulUserid, CONN pConn) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int GetUserid(CONN pConn, LoginParam loginparam) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Boolean SendKickOutCmd(CONN pConn, int kickout_param) {
		// TODO Auto-generated method stub
		return null;
	}
	

}
